package com.ruowei.modules.foodOrder.web.rest;

import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.ruowei.common.querydsl.OptionalBooleanBuilder;
import com.ruowei.modules.foodOrder.domain.*;
import com.ruowei.modules.foodOrder.domain.enumeration.OrderStatus;
import com.ruowei.modules.foodOrder.repository.OrderRepository;
import com.ruowei.modules.foodOrder.web.dto.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@RestController
@RequestMapping("/api")
@Api(tags = "统计相关")
@Transactional
public class StatisticalResource {

    private final Logger log = LoggerFactory.getLogger(StatisticalResource.class);

    private final OrderRepository orderRepository;
    private final JPAQueryFactory queryFactory;

    private final QMerchant qMerchant = QMerchant.merchant;
    private final QMerchandise qMerchandise = QMerchandise.merchandise;
    private final QOrder qOrder = QOrder.order;
    private final QOrderItem qOrderItem = QOrderItem.orderItem;
    private final QCouriers qCouriers = QCouriers.couriers;

    public StatisticalResource(OrderRepository orderRepository, JPAQueryFactory queryFactory) {
        this.orderRepository = orderRepository;
        this.queryFactory = queryFactory;
    }


    @GetMapping("/getOrderVolumeAndAmountForDay")
    @ApiOperation(value = "统计本月订单量和销售额")
    public ResponseEntity<List<StatisticalMouthDTO>> getOrderVolumeAndAmountForDay() {

        return ResponseEntity.ok(orderRepository.getOrderVolumeAndAmountForMouth());
    }


    @GetMapping("/getOrderVolumeAndAmount")
    @ApiOperation(value = "统计-日/月/全部点餐数据")
    public ResponseEntity<SaleDataAllDTO> getOrderVolumeAndAmount(@RequestParam(required = false) String merchantCode) throws CloneNotSupportedException {
        //需统计已送达及已退款的订单
        SaleDataAllDTO result = new SaleDataAllDTO();
        OptionalBooleanBuilder optionalBooleanBuilder = new OptionalBooleanBuilder();
        optionalBooleanBuilder.notEmptyAnd(qOrder.merchantCode::eq, merchantCode)
            .notEmptyAnd(qOrder.deleteStatus::eq, false);
        BooleanBuilder booleanBuilder = optionalBooleanBuilder.build();
        //本日统计
        BooleanBuilder todayBuilder = booleanBuilder.clone().and(qOrder.createDate.eq(LocalDate.now()));
        result.setToday(orderStatistical(todayBuilder));
        //本月统计
        BooleanBuilder mouthBuilder = booleanBuilder.clone().and(qOrder.createDate.between(LocalDate.of(LocalDate.now().getYear(), LocalDate.now().getMonthValue(), 1), LocalDate.now()));
        result.setMouth(orderStatistical(mouthBuilder));
        //全部统计
        result.setAll(orderStatistical(booleanBuilder));

        return ResponseEntity.ok(result);
    }

    @GetMapping("/getOrderVolumeAndAmountForYear")
    @ApiOperation(value = "统计今年订单量和销售额")
    public ResponseEntity<List<StatisticalYearDTO>> getOrderVolumeAndAmountForYear() {
        // 只统计已送达的订单数据
        return ResponseEntity.ok(orderRepository.getOrderVolumeAndAmountForYear());
    }


    @GetMapping("/getMerchantSort")
    @ApiOperation(value = "获取商家排行")
    public ResponseEntity<List<MerchantSortDTO>> getMerchantSort(@RequestParam LocalDate startDate, @RequestParam LocalDate endDate, @RequestParam int flag) {
        // 只统计已送达的订单数据
        Stream<MerchantSortDTO> stream = queryFactory.select(Projections.bean(MerchantSortDTO.class, qMerchant.merchantName, qOrder.totalAmount.count().as("count"), qOrder.totalAmount.sum().as("amount")))
            .from(qMerchant)
            .leftJoin(qOrder).on(qMerchant.merchantCode.eq(qOrder.merchantCode)
                .and(qOrder.status.eq(OrderStatus.DELIVERED))
                .and(qOrder.createDate.between(startDate, endDate)))
            .groupBy(qMerchant.merchantName)
            .fetch().stream().peek(merchantSortDTO -> {
                merchantSortDTO.setAmount(merchantSortDTO.getAmount() == null ? BigDecimal.ZERO : merchantSortDTO.getAmount());
            });
        List<MerchantSortDTO> result = new ArrayList<>();
        List<List<MerchantSortDTO>> list;
        final int[] sort = {1};
        if (flag == 1) {
            //按订单量排序
            list = stream.collect(Collectors.groupingBy(MerchantSortDTO::getCount))
                .entrySet().stream().sorted((s1, s2) -> -Double.compare(s1.getKey(), s2.getKey())).map(Map.Entry::getValue).collect(Collectors.toList());
        } else {
            //按销售额排序
            list = stream.collect(Collectors.groupingBy(MerchantSortDTO::getAmount))
                .entrySet().stream().sorted((s1, s2) -> -Double.compare(s1.getKey().doubleValue(), s2.getKey().doubleValue())).map(Map.Entry::getValue).collect(Collectors.toList());
        }
        list.forEach(merchantSortDTOList -> {
            for (MerchantSortDTO merchantSortDTO : merchantSortDTOList) {
                merchantSortDTO.setSort(sort[0]);
                result.add(merchantSortDTO);
            }
            sort[0] += merchantSortDTOList.size();
        });

        return ResponseEntity.ok(result);
    }


    @GetMapping("/getMerchandiseSort")
    @ApiOperation(value = "获取商品排行")
    public ResponseEntity<List<MerchandiseSortDTO>> getMerchandiseSort(@RequestParam int flag) {
        // 只统计已送达的订单数据
        Stream<MerchandiseSortDTO> stream = orderRepository.getMerchandiseSort().stream().map(merchandiseSortSqlDTO -> {
            MerchandiseSortDTO merchandiseSortDTO = new MerchandiseSortDTO();
            merchandiseSortDTO.setMerchandiseName(merchandiseSortSqlDTO.getMerchandiseName());
            merchandiseSortDTO.setMerchantName(merchandiseSortSqlDTO.getMerchantName());
            merchandiseSortDTO.setOrderCount(merchandiseSortSqlDTO.getOrderCount());
            merchandiseSortDTO.setSaleCount(merchandiseSortSqlDTO.getSaleCount());
            merchandiseSortDTO.setAmount(merchandiseSortSqlDTO.getAmount());
            return merchandiseSortDTO;
        });
        List<MerchandiseSortDTO> result = new ArrayList<>();
        List<List<MerchandiseSortDTO>> list;
        final int[] sort = {1};
        if (flag == 1) {
            //按订单量排序
            list = stream.collect(Collectors.groupingBy(MerchandiseSortDTO::getOrderCount))
                .entrySet().stream().sorted((s1, s2) -> -Double.compare(s1.getKey(), s2.getKey())).map(Map.Entry::getValue).collect(Collectors.toList());
        } else if (flag == 2) {
            //按销售数排序
            list = stream.collect(Collectors.groupingBy(MerchandiseSortDTO::getSaleCount))
                .entrySet().stream().sorted((s1, s2) -> -Double.compare(s1.getKey().doubleValue(), s2.getKey().doubleValue())).map(Map.Entry::getValue).collect(Collectors.toList());
        } else {
            //按销售总额排序
            list = stream.collect(Collectors.groupingBy(MerchandiseSortDTO::getAmount))
                .entrySet().stream().sorted((s1, s2) -> -Double.compare(s1.getKey().doubleValue(), s2.getKey().doubleValue())).map(Map.Entry::getValue).collect(Collectors.toList());
        }
        list.forEach(merchandiseSortDTOList -> {
            for (MerchandiseSortDTO merchandiseSortDTO : merchandiseSortDTOList) {
                merchandiseSortDTO.setSort(sort[0]);
                result.add(merchandiseSortDTO);
            }
            sort[0] += merchandiseSortDTOList.size();
        });

        return ResponseEntity.ok(result);
    }


    @GetMapping("/getCourierSort")
    @ApiOperation(value = "获取配送员排行")
    public ResponseEntity<List<CourierSortDTO>> getCourierSort(@RequestParam int flag, @RequestParam(required = false) Integer time) {
        // 只统计已送达的订单数据
        Stream<CourierSortDTO> stream = queryFactory.select(Projections.bean(CourierSortDTO.class, qCouriers.name, qOrder.id.count().as("count"),
            qOrder.receiveTime.minute().subtract(qOrder.deliveryTime.minute())
                .add((qOrder.receiveTime.hour().subtract(qOrder.deliveryTime.hour())).multiply(60))
                .add((qOrder.receiveTime.dayOfYear().subtract(qOrder.deliveryTime.dayOfYear())).multiply(60 * 24))
                .add((qOrder.receiveTime.year().subtract(qOrder.deliveryTime.year()).multiply(365 * 24 * 60)))
                .sum().as("time")))
            .from(qCouriers)
            .leftJoin(qOrder).on(qCouriers.courierCode.eq(qOrder.courierCode)
                .and(qOrder.status.eq(OrderStatus.DELIVERED)))
            .groupBy(qCouriers.name, qCouriers.courierCode)
            .fetch().stream().peek(courierSortDTO -> courierSortDTO.setTime(courierSortDTO.getCount() == 0 ? 0 : Integer.parseInt(String.valueOf(courierSortDTO.getTime() / courierSortDTO.getCount()))));
        if (time != null) {
            stream = stream.filter(courierSortDTO -> courierSortDTO.getTime().equals(time));
        }
        List<CourierSortDTO> result = new ArrayList<>();
        List<List<CourierSortDTO>> list;
        final int[] sort = {1};
        if (flag == 1) {
            //按单数排序
            list = stream.collect(Collectors.groupingBy(CourierSortDTO::getCount))
                .entrySet().stream().sorted((s1, s2) -> -Double.compare(s1.getKey(), s2.getKey())).map(Map.Entry::getValue).collect(Collectors.toList());
        } else {
            //按送餐时间排序
            list = stream.collect(Collectors.groupingBy(CourierSortDTO::getTime))
                .entrySet().stream().sorted((s1, s2) -> -Double.compare(s1.getKey(), s2.getKey())).map(Map.Entry::getValue).collect(Collectors.toList());
        }
        list.forEach(courierSortDTOList -> {
            for (CourierSortDTO courierSortDTO : courierSortDTOList) {
                courierSortDTO.setSort(sort[0]);
                result.add(courierSortDTO);
            }
            sort[0] += courierSortDTOList.size();
        });

        return ResponseEntity.ok(result);
    }


    private SaleDataDTO orderStatistical(BooleanBuilder booleanBuilder) {
        SaleDataDTO saleDataDTO = new SaleDataDTO();
        JPAQuery<BigDecimal> query = queryFactory.select(qOrder.totalAmount)
            .from(qOrder)
            .where(booleanBuilder)
            .where(qOrder.status.in(OrderStatus.DELIVERED, OrderStatus.REFUNDED));
        Integer orderNum = Integer.parseInt(String.valueOf(query.fetchCount()));
        BigDecimal amount = query.fetch().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal unit = orderNum.equals(0) ? BigDecimal.ZERO : amount.divide(new BigDecimal(orderNum), 2, BigDecimal.ROUND_HALF_UP);
        JPAQuery<BigDecimal> returnQuery = queryFactory.select(qOrder.totalAmount)
            .from(qOrder)
            .where(booleanBuilder)
            .where(qOrder.status.eq(OrderStatus.REFUNDED));
        Integer returnNum = Integer.parseInt(String.valueOf(returnQuery.fetchCount()));
        BigDecimal returnAmount = returnQuery.fetch().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        saleDataDTO.setOrderNum(orderNum);
        saleDataDTO.setAmount(amount);
        saleDataDTO.setUnit(unit);
        saleDataDTO.setReturnNum(returnNum);
        saleDataDTO.setReturnAmount(returnAmount);

        return saleDataDTO;
    }
}
